Java AI 核心引擎:30 天從零打造可擴展的智慧 Agent 函式庫
本篇是 IT 鐵人賽系列文章的第3天,將深入 LangChain4j 的 AiServices,用更優雅、更符合介面導向的方式進行 AI 開發。
在昨天我們直接使用 ChatLanguageModel
進行 AI 對話,這是一種命令式(Imperative)的開發方式。而 AiServices
提供了聲明式(Declarative)的開發模式。從實際開發經驗來看,兩者在開發體驗上有著本質的差異。
ChatLanguageModel(命令式開發)
使用 ChatLanguageModel 時,需要直接呼叫模型的 generate()
方法,並且手動管理所有的提示詞設定。當需要加入系統訊息時,必須在每次呼叫時手動拼接,例如:chatModel.generate("你是專業助理。" + userMessage)
。這種方式雖然簡單直接,但隨著業務邏輯的複雜化,相關程式碼往往會分散在各個服務類別中。
AiServices(聲明式開發)
相對地,AiServices 能透過介面定義來描述 AI 服務的行為。透過 @SystemMessage
註解,框架會自動處理系統提示詞的設定,開發者只需要專注在業務邏輯的定義上。所有 AI 相關的行為都集中在介面定義中,符合物件導向的封裝原則。
從維護角度來看,ChatLanguageModel 的使用方式容易產生重複程式碼,特別是系統提示詞的管理。當需要調整 AI 的角色設定時,可能需要修改多個地方。而 AiServices 將這些設定集中管理,修改時只需要更新介面的註解即可。
AiServices
透過 Java 介面定義 AI 服務的行為,框架自動產生實作:
// 定義介面
public interface Assistant {
String chat(String userMessage);
}
// 使用 AiServices.create() 建立介面的實作(透過動態代理)
Assistant assistant = AiServices.create(Assistant.class, chatModel);
// 注意:這只是建立實例,需要透過 @Bean 註解才能註冊到 Spring 容器
在 src/main/java/org/example/aiagentdemo/service
目錄建立 Assistant.java
:
package org.example.aiagentdemo.service;
import dev.langchain4j.service.SystemMessage;
/**
* AI 助理服務介面
*
* 使用 LangChain4j 的 AiServices 功能,透過聲明式方式定義 AI 服務。
* 此介面將由 LangChain4j AiServices 框架實現,提供更優雅的 AI 互動方式。
*/
public interface Assistant {
/**
* 與 AI 助理進行對話
*
* @param userMessage 使用者輸入的訊息
* @return AI 助理的回應
*/
@SystemMessage("你是一個友善且專業的 AI 助理。請用繁體中文回應,並提供有用、準確的資訊。")
String chat(String userMessage);
}
由於我們使用 LangChain4j 0.36.2 版本,需要手動建立 AiServices 實例。
在 src/main/java/org/example/aiagentdemo/config
目錄建立 AiServiceConfig.java
:
package org.example.aiagentdemo.config;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.service.AiServices;
import org.example.aiagentdemo.service.Assistant;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* AI 服務配置類別
*
* 負責建立和配置 LangChain4j AiServices 相關的 Bean。
* LangChain4j 提供簡潔的 create() 方法來建立 AI 服務實例。
*/
@Configuration
public class AiServiceConfig {
/**
* 建立 Assistant Bean
*
* 使用 AiServices.create() 方法建立 Assistant 介面的實現,
* 這是官方推薦的簡潔方式,適用於基本的 AI 服務配置。
*
* @param chatLanguageModel Spring 自動配置的 ChatLanguageModel Bean
* @return Assistant 實例
*/
@Bean
public Assistant assistant(ChatLanguageModel chatLanguageModel) {
return AiServices.create(Assistant.class, chatLanguageModel);
}
}
LangChain4j 提供兩種建立 AiServices 的方式:
1. 簡潔方式(推薦):
AiServices.create(Assistant.class, chatLanguageModel)
2. Builder 方式(進階用法):
AiServices.builder(Assistant.class)
.chatLanguageModel(chatLanguageModel)
.tools(customTools) // 可選:加入工具
.chatMemory(chatMemory) // 可選:加入記憶
.build()
@Bean
註解將 AiServices 註冊到 Spring 容器ChatLanguageModel
在 src/main/java/org/example/aiagentdemo/runner
目錄建立 AiServiceRunner.java
:
package org.example.aiagentdemo.runner;
import org.example.aiagentdemo.service.Assistant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
/**
* AI 服務執行器 - 示範 AiServices 聲明式 AI 服務使用方式
*
* 使用 AiServices.create() 建立的 Assistant Bean,展示聲明式 AI 服務開發模式。
* 相較於直接使用 ChatLanguageModel,AiServices 提供:
* - 聲明式介面設計,符合 Spring Bean 管理模式
* - 自動處理系統訊息與提示詞模板(@SystemMessage)
* - 類型安全的介面設計,支援結構化輸出
* - 更好的程式碼組織和維護性
*/
@Component
public class AiServiceRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(AiServiceRunner.class);
// 注入透過 AiServiceConfig 手動建立的 Assistant Bean
@Autowired
private Assistant assistant;
@Override
public void run(String... args) throws Exception {
logger.info("========== 開始 AiServices 測試 ==========");
// 測試 1:聲明式服務問候
testServiceGreeting();
// 測試 2:專業AI助理回應
testProfessionalAssistant();
// 測試 3:比較聲明式與直接呼叫的差異
testServiceApproach();
logger.info("========== AiServices 測試完成 ==========");
}
/**
* 測試聲明式 AI 服務的基本對話
*/
private void testServiceGreeting() {
logger.info("\n--- 測試 1:AiService 聲明式問候 ---");
String question = "請問你是誰?你有什麼功能?";
logger.info("使用者: {}", question);
String response = assistant.chat(question);
logger.info("AI 助理回應: {}", response);
}
/**
* 測試 AI 助理的專業回應能力
*/
private void testProfessionalAssistant() {
logger.info("\n--- 測試 2:專業 AI 助理回應 ---");
String question = "請解釋什麼是 Spring Boot 的依賴注入,並舉一個簡單的例子。";
logger.info("使用者: {}", question);
String response = assistant.chat(question);
logger.info("AI 助理回應: {}", response);
}
/**
* 展示聲明式 AI 服務的優勢
*/
private void testServiceApproach() {
logger.info("\n--- 測試 3:聲明式服務優勢展示 ---");
String question = "請用繁體中文說明 AiServices 相比直接使用 ChatLanguageModel 的優點。";
logger.info("使用者: {}", question);
String response = assistant.chat(question);
logger.info("AI 助理回應: {}", response);
}
}
# 清除並編譯專案
./mvnw clean compile
./mvnw spring-boot:run
當應用程式啟動後,會看到類似以下的輸出:
========== 開始 AiServices 測試 ==========
--- 測試 1:AiService 聲明式問候 ---
使用者: 請問你是誰?你有什麼功能?
AI 助理回應: 我是一個友善且專業的 AI 助理。我能夠理解和回應使用者的問題、提供資訊和建議...
--- 測試 2:專業 AI 助理回應 ---
使用者: 請解釋什麼是 Spring Boot 的依賴注入,並舉一個簡單的例子。
AI 助理回應: Spring Boot 依賴注入是一種設計模式,用於管理類別之間的依存關係...
--- 測試 3:聲明式服務優勢展示 ---
使用者: 請用繁體中文說明 AiServices 相比直接使用 ChatLanguageModel 的優點。
AI 助理回應: AiServices 相比直接使用 ChatLanguageModel 有以下優點...
========== AiServices 測試完成 ==========
ChatLanguageModel 方式(命令式):
@Autowired
private ChatLanguageModel chatModel;
public void doChat() {
// 方法 1:簡單字串拼接(不推薦,易產生格式問題)
String response = chatModel.generate("你是專業助理。" + userMessage);
// 方法 2:使用 ChatMessage 物件(推薦做法)
List<ChatMessage> messages = Arrays.asList(
SystemMessage.from("你是專業助理。"),
UserMessage.from(userMessage)
);
Response<AiMessage> response = chatModel.generate(messages);
String result = response.content().text();
// 需要引入的類別:
// import dev.langchain4j.data.message.*;
// import dev.langchain4j.model.output.Response;
}
AiServices 方式(聲明式):
@Autowired
private Assistant assistant;
public void doChat() {
String response = assistant.chat(userMessage);
// @SystemMessage 自動處理系統提示詞
}
@SystemMessage
註解自動處理系統指示今天的實作展示了從命令式到聲明式程式設計的轉變:
這種轉變讓程式碼更加簡潔、可維護,並且更符合物件導向設計原則。
明天將:
感謝閱讀,明天繼續努力!
Day 3 完成 | 明天繼續 AI 開發之旅!